import { hasChanged, isObject } from "../share"
import { trackEffect, triggerEffect, isTracking } from "./effect"
import { reactive } from "./reactive"

class RefImpl {
  private _value:any
  private _rawValue: any
  public __v_isRef = true
  dep
  constructor(value) {
    this._rawValue = value
    this._value = convert(value)
    this.dep = new Set()
  }

  get value() {
    trackRefValue(this)
    return this._value
  }

  set value(newVal) {
    if(hasChanged(newVal, this._rawValue)) {
      this._rawValue = newVal
      this._value = convert(newVal)
      triggerEffect(this.dep)
    } 
  }
}

export function ref(value) {
  return new RefImpl(value)
}

function trackRefValue(ref) {
  if(isTracking()) {
    trackEffect(ref.dep)
  }
}

function convert(value) {
  return isObject(value)? reactive(value) : value
}

export function isRef(ref) {
  return !!ref.__v_isRef
}

export function unRef(ref) {
  return isRef(ref) ? ref.value :  ref
}

export function proxyRefs(obj) {
  return new Proxy(obj, {
    get(target, key) {
      return unRef(Reflect.get(target, key))
    },
    set(target, key, newVal) {
      if(isRef(target[key]) && !isRef(newVal)) {
        return target[key].value = newVal
      }
      return Reflect.set(target, key, newVal)
    }
  })
}